package com.gjp.processdemo.controller;

import com.gjp.processdemo.utils.ImageUtil;
import com.gjp.processdemo.utils.UserUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.form.FormProperty;
import org.flowable.engine.form.TaskFormData;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@RestController
public class TaskController {
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private FormService formService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private ProcessEngineConfiguration processEngineConfiguration;

    /**
     * 查询我的任务列表，包含可接取的任务
     *
     * @return
     */
    @RequestMapping("/myTask")
    public ModelAndView getTaskList() {
        ModelAndView modelAndView = new ModelAndView("my-task");
        //获取当前登录用户
        String username = UserUtil.getCurrentUsername();

        //获取我的任务，以及未指定办理人的任务
        List<Task> myTaskList = taskService.createTaskQuery()
                .taskCandidateOrAssigned(username)
                .active()
                .list();

        //获取还未指定办理人的任务
        myTaskList.addAll(
                taskService.createTaskQuery()
                        .taskUnassigned()
                        .active()
                        .list()
        );

        modelAndView.addObject("taskList", myTaskList);
        return modelAndView;
    }

    /**
     * 接取任务
     *
     * @param taskId
     * @return
     */
    @RequestMapping("/claim/{taskId}")
    public ModelAndView claimTask(@PathVariable("taskId") String taskId) throws UnsupportedEncodingException {
        ModelAndView modelAndView = new ModelAndView();
        String username = UserUtil.getCurrentUsername();
        //接收任务
        taskService.claim(taskId, username);
        modelAndView.setViewName("redirect:/myTask");
        return modelAndView;
    }

    /**
     * 处理任务
     *
     * @param taskId
     * @return
     */
    @RequestMapping("/handle/{taskId}")
    public ModelAndView handleTask(@PathVariable("taskId") String taskId) {
        ModelAndView modelAndView = new ModelAndView("handleTask");
        //办理任务
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .singleResult();
        modelAndView.addObject("task", task);
        if (StringUtils.isEmpty(task.getFormKey())) {
            //动态表单
            List<FormProperty> formPropertyList = formService
                    .getTaskFormData(taskId)
                    .getFormProperties();
            //获取历史变量数据，用以前台显示
            List<HistoricVariableInstance> historicVariableInstances = historyService
                    .createHistoricVariableInstanceQuery()
                    .processInstanceId(task.getProcessInstanceId())
                    .list();
            modelAndView.addObject("historicVariableInstances", historicVariableInstances);
            modelAndView.addObject("formPropertyList", formPropertyList);
        } else {
            //外置表单
            Object renderedTaskForm = formService.getRenderedTaskForm(taskId);
            modelAndView.addObject("renderedTaskForm", renderedTaskForm);
        }
        return modelAndView;
    }


    /**
     * 指派任务，使用setAssignee形式
     *
     * @param assignName
     * @param taskId
     * @return
     */
    @RequestMapping("/assignTo")
    public String assignTo(
            @RequestParam("assignName") String assignName
            , @RequestParam("taskId") String taskId) {
        // TODO 验证用户合法性
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        // 修改办理人
        task.setAssignee(assignName);
        // 保存当前任务
        taskService.saveTask(task);
        return "ok";
    }

    /**
     * 完成任务
     *
     * @param taskId
     * @param request
     * @return
     */
    @RequestMapping("/complete")
    public ModelAndView completeTask(@RequestParam("taskId") String taskId
            , HttpServletRequest request) {
        ModelAndView modelAndView = new ModelAndView();
        // TODO 需要验证这个任务是否属于当前用户
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (StringUtils.isEmpty(task.getFormKey())) {
            //动态表单
            TaskFormData taskFormData = formService.getTaskFormData(taskId);
            Map<String, Object> variable = new HashMap<>();
            for (FormProperty formProperty : taskFormData.getFormProperties()) {
                String key = formProperty.getId();
                String value = request.getParameter(formProperty.getId());
                //如果参数必填，但是入参为空，则抛出异常
                if (formProperty.isRequired() && StringUtils.isEmpty(value)) {
                    throw new RuntimeException("参数不能为空");
                }
                variable.put(key, value);
            }
            //动态表单的提交任务
            taskService.complete(taskId, variable);
        } else {
            //外置表单
            Map<String, String> variable = new HashMap<>();
            //为了和其他参数做区分，需要入库保存的字段都加了 fp_ 前缀，方便区分,意思就是 Form Propertie
            Map<String, String[]> parameterMap = request.getParameterMap();
            for (String key : parameterMap.keySet()) {
                if (key.startsWith("fp_")) {
                    String value = parameterMap.get(key)[0];
                    variable.put(key.replace("fp_", ""), value);
                }
            }
            //外置表单提交任务
            formService.submitTaskFormData(taskId, variable);
        }
        //提交任务后，跳转到我的任务页面
        modelAndView.setViewName("redirect:/myTask");
        return modelAndView;
    }

    /**
     * 查看流程定义图片
     *
     * @param processDefinitionId
     * @return
     * @throws IOException
     */
    @RequestMapping("/process/image/{processDefinitionId}")
    public String getImage(@PathVariable("processDefinitionId") String processDefinitionId) throws IOException {
        //获取流程定义对象性
//        ProcessDefinition processDefinition = repositoryService
//                .createProcessDefinitionQuery()
//                .processDefinitionId(processDefinitionId)
//                .singleResult();
//        if (processDefinition == null){
//            return "";
//        }

        //根据流程定义对象的 DeploymentId 获取流程图
        BpmnModel bpmnModel = this.repositoryService.getBpmnModel(processDefinitionId);
        InputStream is = processEngineConfiguration.getProcessDiagramGenerator()
                .generateDiagram(
                        bpmnModel
                        , "png"
                        , Collections.emptyList()
                        , Collections.emptyList()
                        , processEngineConfiguration.getActivityFontName()
                        , processEngineConfiguration.getLabelFontName()
                        , processEngineConfiguration.getAnnotationFontName()
                        , processEngineConfiguration.getClassLoader()
                        , 1.0
                        , false);
        return ImageUtil.handleInputStream2Base64(is);
    }

    /**
     * 查看流程图，当前执行环节
     *
     * @param processInstanceId
     * @return
     * @throws IOException
     */
    @RequestMapping("/activeProcess/image/{processInstanceId}")
    public String getActiveProcessImage(@PathVariable("processInstanceId") String processInstanceId) throws IOException {
        //查询流程实例
        ProcessInstance pi = this.runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (pi == null) {
            return "";
        }
        BpmnModel bpmnModel = this.repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        //得到正在执行的环节
        List<String> activeIds = this.runtimeService.getActiveActivityIds(pi.getId());
        InputStream is = processEngineConfiguration.getProcessDiagramGenerator()
                .generateDiagram(
                        bpmnModel
                        , "png"
                        , activeIds
                        , Collections.emptyList()
                        , processEngineConfiguration.getActivityFontName()
                        , processEngineConfiguration.getLabelFontName()
                        , processEngineConfiguration.getAnnotationFontName()
                        , processEngineConfiguration.getClassLoader()
                        , 1.0
                        , false);
        return ImageUtil.handleInputStream2Base64(is);
    }

}
